import java.awt.Rectangle;
import java.util.Random;

import ij.IJ;
import ij.ImagePlus;
import ij.gui.NewImage;
import ij.plugin.filter.PlugInFilter;
import ij.process.Blitter;
import ij.process.ImageProcessor;

/**
 * 
 */

/**
 * @author Francesco
 *
 */
public class DrosteRectangular_ implements PlugInFilter {
	private int imgCols,imgCols2; 
	private int imgRows,imgRows2;
	private double imgRatio; 
	private Random generator=new Random();
	
	private double r1=0.2;
	private double r2=0.8; 
	
	/* (non-Javadoc)
	 * @see ij.plugin.filter.PlugInFilter#run(ij.process.ImageProcessor)
	 */
	public void run(ImageProcessor ip) {
		 //get width, height and the region of interest
			int w = ip.getWidth();     
			int h = ip.getHeight();    
			
			this.imgCols=w;
			this.imgRows=h;
			this.imgRows2=this.imgRows; 
			this.imgCols2=this.imgCols; 
			this.imgRatio=(this.imgRows+0.0)/this.imgCols;
			//this.setSize(this.imgCols,this;imgRows);
			if(imgRows>imgCols)
				this.imgCols2=this.imgRows; 
			else
				this.imgRows2=this.imgCols; 
			    
			
			
			
			Rectangle roi = ip.getRoi();
			System.out.println(w*h+" "+w+" "+h+" "+roi.width); 

			// create a new image with the same size and copy the pixels of the original image
			ImagePlus inverted = NewImage.createRGBImage ("Inverted image", w, h, 1, NewImage.FILL_BLACK);
			ImageProcessor inv_ip = inverted.getProcessor();
			inv_ip.copyBits(ip,0,0,Blitter.COPY);

			int[] basepixels = (int[]) inv_ip.getPixels();
			int[] pixels=new int[this.imgCols2*this.imgRows2];
			
			 double alpha=Math.atan(Math.log(r2/r1)/(2*Math.PI));
			 double cosAlpha=Math.cos(alpha);
			 double sinAlpha=Math.sin(alpha);
			 double provProd=Math.pow(r1/r2,cosAlpha*cosAlpha); 
			 double provInner=cosAlpha*sinAlpha*Math.log(r1/r2);
			 
			 double Afactor=provProd*Math.cos(provInner);
			 double Bfactor=provProd*Math.sin(provInner);
			 
			   /*for(int j=0;j<100000;j++){
			    	for(int i=0;i<1000000;i++){
			    		int xrow=generator.nextInt(imgRows);
				    	int ycol=generator.nextInt(imgCols);*/
			   for(int iter=0;iter<1000;iter++){
			    for(int xrow=0;xrow<imgRows;xrow++){
			    	for(int ycol=0;ycol<imgCols;ycol++){
				    	// transform in [-1,1]x[-1,1]
				    	double x=(xrow+0.0)/imgRows*2.0-1.0;
				    	double y=(ycol+0.0)/imgCols*2.0-1.0; 
				    	double r=Math.sqrt(x*x+y*y); 
				    	//if((r>r1)&&(r<r2)){
				    	// Condition for a simple rectangle : THe only change compared to the previous program !
				    	if(((x>r1)&&(x<r2)&&(y<r2)&&(y>-r2))||
				    			((x<-r1)&&(x>-r2)&&(y<r2)&&(y>-r2))||
				    			((y>r1)&&(y<r2)&&(x>-r2)&&(x<r2))||
				    			((y<-r1)&&(y>-r2)&&(x>-r2)&&(x<r2)))
				    	{
			    		double theta=0.0; 
			    		if(Math.abs(x)<1E-6)theta=Math.PI/2; 
			    		if((Math.abs(x)<1E-6)&&(x<0))theta=-Math.PI/2; 
			    		if(Math.abs(x)>=1E-6){
			    			theta=Math.atan(y/x);
			    			if((x<0)&&(y>0)) theta=theta+Math.PI; 
			    			if((x<0)&&(y<0))theta=theta+Math.PI;
			    		}
			    		
			    		double newX=cosAlpha*(cosAlpha*Math.log(r/r1)-theta*sinAlpha); 
			    		double newY=cosAlpha*(theta*cosAlpha+sinAlpha*Math.log(r/r1));
			    		
			    		
			    		// Now z<-- exp(z)
			    		double power=Math.exp(newX); 
			    		newX=power*Math.cos(newY); 
			    		newY=power*Math.sin(newY);
			    		
			    		
			    		
			    		double InewX=(newX+1)*imgRows2/2.0; 
			    		double InewY=(newY+1)*imgCols2/2.0;
			    		int X=(int)InewX; 
			    		int Y=(int)InewY; 
			    		//System.out.println(x+" "+y+" "+X+" "+Y); 
			    		int devX=generator.nextInt(5)-2;
			    		int devY=generator.nextInt(5)-2; 
			    		if(((X+devX)*imgCols2+(Y+devY)<pixels.length)&&((X+devX)*imgCols2+(Y+devY)>=0))
			    		if((X+devX>=0)&&(X+devX<imgRows2)&&(Y+devY>=0)&&(Y+devY<imgCols2))
			    			//if(pixels[(X+devX)*imgCols2+(Y+devY)]==0)
			    				pixels[(X+devX)*imgCols2+(Y+devY)]=basepixels[xrow*imgCols+ycol];
			    		
			    		
			    		for(int in=0;in<7;in++){
			    			double pronewX=newX*Afactor-newY*Bfactor; 
			    			double pronewY=Bfactor*newX+Afactor*newY;
			    			
			    			InewX=(pronewX+1)*imgRows2/2.0; 
				    		InewY=(pronewY+1)*imgCols2/2.0;
				    		devX=0; 
				    		devY=0;
				    		if(in==0){
				    		devX=generator.nextInt(4)-2; 
				    		devY=generator.nextInt(4)-2;
				    		}
				    		X=(int)InewX; 
				    		Y=(int)InewY; 
				    		if((X+devX>=0)&&(X+devX<imgRows2)&&(Y+devY>=0)&&(Y+devY<imgCols2))
				    		if(((devX+X)*imgCols2+Y+devY<pixels.length)&& ((X+devX)*imgCols2+Y+devY>=0))
				    			//if(pixels[(X+devX)*imgCols2+Y+devY]==0)
				    				pixels[(X+devX)*imgCols2+Y+devY]=basepixels[xrow*imgCols+ycol];
				    		newX=pronewX;
				    		newY=pronewY;
			    		}
			    	
					}
			    
			    	}
			    	System.out.println("un tour");
			    	inv_ip.setPixels(pixels); 
					 inverted.show();
					 inverted.updateAndDraw();
					// inv_ip.setPixels(basepixels); 
					//basepixels = (int[]) inv_ip.getPixels();
			  
			   }
			 
			 
			 inv_ip.setPixels(pixels); 
			 inverted.show();
			 inverted.updateAndDraw();
			   }
			
	}

	/* (non-Javadoc)
	 * @see ij.plugin.filter.PlugInFilter#setup(java.lang.String, ij.ImagePlus)
	 */
	
	public int setup(String arg, ImagePlus imp) {
		if (arg.equals("about"))
			{showAbout(); return DONE;}
	            return DOES_RGB+NO_CHANGES;

	}
	
	void showAbout() {
		IJ.showMessage("Droste effect",
			"Escher-like droste effect"
		); 

	}
}